package model;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import javax.swing.JFileChooser;
import view.MaquinaTuringView;

/**
 * @author lucasamaral
 * @author fernando
 */
public class Arquivo {

  private BufferedReader bufferedReader;
  private BufferedWriter bufferedWriter;
  public File arquivoEntrada = null;

  /**
   * Método get para a objeto ArquivoEntrada do tipo File.
   * @return Retorno do tipo getArquivoEntrada
   */
  public File getArquivoEntrada() {
    return arquivoEntrada;
  }

  /**
   *  Método set para a objeto ArquivoEntrada do tipo File.
   * @param arquivoEntrada Recebe objeto do tipo getArquivoEntrada
   */
  public void setArquivoEntrada(File arquivoEntrada) {
    this.arquivoEntrada = arquivoEntrada;
  }
        
  /**
   * Método que grava os dados da fita no arquivo de saída.
   * @param resultados Objeto do tipo Map com Key do tipo Integer e Value do tipo String
   */
  public void gravaDados(Map<Integer, String> resultados) {
    try {
      bufferedWriter = new BufferedWriter(new FileWriter("resultado.txt"));
      bufferedWriter.write("\t***Dados finais das fitas após o processamento***\n\n");
      for (Map.Entry<Integer, String> resultado: resultados.entrySet()) {
        bufferedWriter.write("Fita " + resultado.getKey() + ": " + resultado.getValue());
        bufferedWriter.newLine();
      }
      bufferedWriter.close();
    } catch(Exception e) {/**/}
  }
  
  /**
   * Método que abstrai as Entradas da MT.
   * @param maquinaTuring Objeto do tipoMaquinaTuring
   * @param transições Objeto Collection do tipo Transicao
   */
  public void populaEntradas(MaquinaTuring maquinaTuring, Collection<Transicao> transições) {
    try {
      bufferedReader = new BufferedReader(new FileReader(arquivoEntrada));
      String linha = bufferedReader.readLine();
      populaColeção(linha, maquinaTuring.getEstados());  //Estados da maquina
      populaColeção(linha, maquinaTuring.getAlfabetoEntrada()); //Alfabeto de Arquivo
      populaColeção(linha, maquinaTuring.getAlfabetoFita()); //Alfabeto da Fita
      linha = populaTransições(linha, transições); //Transições
      maquinaTuring.setTipoMaquina(linha); //Tipo de maquina
      linha = bufferedReader.readLine(); //Casos de teste
      for (int i = 0; i < Integer.valueOf(linha); i++) {
        populaCasosDeTeste(linha, maquinaTuring);
      }
      bufferedReader.close();
    } catch (Exception e) { 
      System.out.println("Erro ao Ler Arquivo!");
    }
  }
  
  /**
   * Método que recebe o arquivo de entrada informado pelo usuário através da interface.
   * @param view
   */
  public void carregaArquivoEntrada(MaquinaTuringView view) {
    JavaFilter filter = new JavaFilter ();
    JFileChooser fc = new JFileChooser ();
    arquivoEntrada = new File ("*.txt");
    // Start in current directory
    fc.setCurrentDirectory(new File("."));
    // Set filter for Java source files.
    fc.setFileFilter(filter);
    // Set to a default name for save.
    fc.setSelectedFile(arquivoEntrada);
    // Open chooser dialog
    arquivoEntrada = fc.getSelectedFile ();
    int resultado = fc.showOpenDialog(view);
    if (resultado == JFileChooser.APPROVE_OPTION) {
      arquivoEntrada = fc.getSelectedFile ();
    }
  }
  
  /**
   * Método que lê os dados da MT do arquivo de entrada. Pode lançar uma exceção
   * do tipo IOException.
   * @param linha Uma String que contém a linha a ser tratada.
   * @param coleção Uma Collection do tipo String.
   **/
  private void populaColeção(String linha, Collection<String> coleção) throws IOException {
    String[] palavras;
    linha = bufferedReader.readLine();
    palavras = linha.split(" ");
    for (String palavra : palavras) {
      coleção.add(palavra);
    }
  }  
  
  /**
   * Método que recebe as linhas com as fitas para os testes e coloca em um ArrayList.
   * @param linha String com a linha do arquivo a ser tratada.
   * @param maquinaTuring Instância do objeto do tipo MaquinaTuring.
   * @throws IOException Excessão possível, pois o método trabalha com arquivos.
   */
  private void populaCasosDeTeste(String linha, MaquinaTuring maquinaTuring) throws IOException {
    linha = bufferedReader.readLine();
    int posição = 0;
    String[] fita = new String[linha.toCharArray().length + 1];
    for (char simbolo : linha.toCharArray()) {
      fita[posição] = simbolo + "";
      posição++;
    }
    maquinaTuring.getCasosDeTeste().add(fita);
  }
  
  /**
   * Método a partir da linha corrente extrai as informações das transições.
   * @param linha String da linha em questão.
   * @param transições Instância de uma Collection do tipo Transicao.
   * @return String retornada com a próxima linha do arquivo.
   * @throws IOException Método pode retornar está excessão, pois trabalha com arquivos.
   */
  private String populaTransições(String linha, Collection<Transicao> transições) throws IOException {
    linha = bufferedReader.readLine();
    String[] palavras;
    while (linha.contains("=")) {
      Transicao transicao = new Transicao();
      palavras = linha.split(",");
      transicao.setEstadoAtual(palavras[0].replace("(", ""));
      transicao.setSimboloAtual(palavras[1].split("=")[0]);
      transicao.setSimboloAtual(transicao.getSimboloAtual().replace(")", ""));
      transicao.setProximoEstado(palavras[1].split("=")[1]);
      transicao.setProximoEstado(transicao.getProximoEstado().replace("(", ""));
      transicao.setProximoSimbolo(palavras[2]);
      transicao.setMovimenta(palavras[3].replace(")", ""));
      transições.add(transicao);
      linha = bufferedReader.readLine();
    }
    return linha;
  }
}
